/*
 * @Author: ljk
 * @Date: 2023-05-30 20:16:20
 * @LastEditors: ljk
 * @LastEditTime: 2023-06-01 15:31:56
 * @Description: 线程互斥与线程同步
 */
#include <iostream>
#include <unistd.h>
#include <string>
#include "Thread.hpp"
#include "lockGuard.hpp"
// #include <pthread.h>
using namespace std;

// 互斥锁封装
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 这是我在外边定义的锁
int tickets = 1000;

void *threadRoutine(void *args)
{
    string message = static_cast<const char *>(args);
    while (true)
    {
        //跳出代码块表示lockguard对象直接析构，同时解锁
        {
            LockGuard lockguard(&mutex); //RAII风格加速
            if (tickets > 0)
            {
                usleep(2000);
                cout << message << " get a tickets: " << tickets-- << endl; // 临界区
            }
            else
            {
                break;
            }
        }

        // 抢完一张票会有后续动作
        usleep(1000);
    }

    return nullptr;
}
int main()
{
    Thread t1(1, threadRoutine, (void *)"thread1");
    Thread t2(2, threadRoutine, (void *)"thread2");
    Thread t3(2, threadRoutine, (void *)"thread3");
    Thread t4(2, threadRoutine, (void *)"thread4");

    t1.run();
    t2.run();
    t3.run();
    t4.run();

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    return 0;
}

// //测试线程封装
// void* threadRun(void* args)
// {
//     std::string message = static_cast<const char*>(args);
//     int cnt = 5;
//     while (cnt)
//     {
//         cout << "I am a thread, " << message << ": " << cnt-- << endl;
//         sleep(1);
//     }
//     return nullptr;
// }
// int main()
// {
//     Thread t1(1, threadRun, (void*)"hello thread1");
//     Thread t2(2, threadRun, (void*)"hello thread2");

//     cout << "thread name: " << t1.threadName() << ", thread id: " << t1.threadId() << ", thread status: " << t1.status() << endl;
//     cout << "thread name: " << t2.threadName() << ", thread id: " << t2.threadId() << ", thread status: " << t2.status() << endl;

//     t1.run();
//     t2.run();

//     cout << "thread name: " << t1.threadName() << ", thread id: " << t1.threadId() << ", thread status: " << t1.status() << endl;
//     cout << "thread name: " << t2.threadName() << ", thread id: " << t2.threadId() << ", thread status: " << t2.status() << endl;

//     t1.join();
//     t2.join();

//     cout << "thread name: " << t1.threadName() << ", thread id: " << t1.threadId() << ", thread status: " << t1.status() << endl;
//     cout << "thread name: " << t2.threadName() << ", thread id: " << t2.threadId() << ", thread status: " << t2.status() << endl;

//     return 0;
// }

// 线程互斥基础
//  细节：
//  1. 凡是访问同一个临界资源的线程，都要进行加锁保护，而且必须加同一把锁，这个是一个游戏规则，不能有例外
//  2. 每一个线程访问临界区之前，得加锁，加锁本质是给 临界区 加锁，加锁的粒度尽量要细一些
//  3. 线程访问临界区的时候，需要先加锁->所有线程都必须要先看到同一把锁->锁本身就是公共资源->锁如何保证自己的安全？-> 加锁和解锁本身就是原子的！
//  4. 临界区可以是一行代码，可以是一批代码
//     a. 线程可能被切换吗？当然可能， 不要特殊化加锁和解锁，还有临界区代码。
//     b. 切换会有影响吗？不会，因为在我不在期间，任何人都没有办法进入临界区，因为他无法成功的申请到锁！因为锁被我拿走了！
//  5. 这也正是体现互斥带来的串行化的表现，站在其他线程的角度，对其他线程有意义的状态就是：锁被我申请(持有锁)，锁被我释放了(不持有锁)， 原子性就体现在这里
//  6. 解锁的过程也被设计成为原子的！
//  7. 锁的原理的理解

// // 临界资源
// int tickets = 1000;                                // 全局变量，共享对象
// //pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 这是我在外边定义的锁

// class TData
// {
// public:
//     TData(const string &name, pthread_mutex_t *mutex):_name(name), _pmutex(mutex)
//     {}
//     ~TData()
//     {}
// public:
//     string _name;
//     pthread_mutex_t *_pmutex;
// };

// void *threadRoutine(void *args)
// {
//     TData* td = static_cast<TData*>(args);
//     while (true)
//     {
//         pthread_mutex_lock(td->_pmutex);
//         if (tickets > 0)
//         {
//             usleep(2000);
//             cout << td->_name << " get a tickets: " << tickets-- << endl; // 临界区
//             pthread_mutex_unlock(td->_pmutex);
//         }
//         else
//         {
//             pthread_mutex_unlock(td->_pmutex);
//             break;
//         }

//         // 抢完一张票会有后续动作
//         usleep(1000);
//     }

//     return nullptr;
// }

// int main()
// {
//     // 局部互斥锁，怎么让所有线程看到并使用呢
//     pthread_mutex_t mutex;
//     pthread_mutex_init(&mutex, nullptr);

//     pthread_t tids[4];
//     int n = sizeof(tids) / sizeof(tids[0]);
//     for (int i = 0; i < n; i++)
//     {
//         //char *name = new char[64];
//         char name[64];
//         snprintf(name, 64, "thread-%d", i + 1);
//         TData* td = new TData(name, &mutex);

//         pthread_create(tids + i, nullptr, threadRoutine, td);
//     }

//     for (int i = 0; i < n; i++)
//     {
//         pthread_join(tids[i], nullptr);
//     }

//     pthread_mutex_destroy(&mutex);
//     return 0;
// }
